package com.whl.mybatis.builder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.springframework.util.Assert;

import com.whl.mybatis.constant.Constants;
import com.whl.mybatis.constant.SqlFormat;
import com.whl.mybatis.mapper.EntityTableMapper;

public class ConfigurationAfterBuilder {

	public static void afterPropertiesSet(Configuration configuration, LanguageDriver languageDriver, List<SqlCommandType> sqlCommandTypes) {
		MapperRegistry mapperRegistry = configuration.getMapperRegistry();
		Collection<Class<?>> mapperInterfaces = mapperRegistry.getMappers();
		for (Class<?> mapperInterface : mapperInterfaces) {
			EntityTableMapper entityMapper = MapperBuilder.getEntityTableMapper(mapperInterface);
			for (SqlCommandType sqlCommandType : sqlCommandTypes) {
				List<String> mappedStatementSuffixs = new ArrayList<>();
				mappedStatementSuffixs
						.add(sqlCommandType.toString().toLowerCase() + StringUtils.capitalize(Constants.SELECTIVE));
				mappedStatementSuffixs.add(sqlCommandType.toString().toLowerCase());
				if (SqlCommandType.DELETE.equals(sqlCommandType) || SqlCommandType.SELECT.equals(sqlCommandType)) {
					mappedStatementSuffixs.add(
							sqlCommandType.toString().toLowerCase() + StringUtils.capitalize(Constants.BY_PRIMARY_KEY));
				}
				for (String mappedStatementSuffix : mappedStatementSuffixs) {
					String sql = "";
					String mappedStatementId = entityMapper.getNamespace() + "." + mappedStatementSuffix;
					switch (sqlCommandType) {
					case INSERT:
						sql = SqlBuilder.buildInsertSql(entityMapper, mappedStatementSuffix);
						break;
					case UPDATE:
						sql = SqlBuilder.buildUpdateSql(entityMapper, mappedStatementSuffix);
						break;
					case SELECT:
						sql = SqlBuilder.buildSelectSql(entityMapper,mappedStatementSuffix);
						break;
					case DELETE:
						sql = SqlBuilder.buildDeleteSql(entityMapper,mappedStatementSuffix);
						break;
					default:
						break;
					}
					// DynamicSqlSource

					Assert.isTrue(!configuration.hasStatement(mappedStatementId),
							mappedStatementId + " has many mappedStatement");
					SqlSource sqlSource = languageDriver.createSqlSource(configuration,
							String.format(SqlFormat.SCRIPT, sql), null);
					MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration,
							mappedStatementId, sqlSource, sqlCommandType);
					if (SqlCommandType.SELECT.equals(sqlCommandType)) {
						List<ResultMap> resultMaps = new ArrayList<>();
						resultMaps.add(configuration
								.getResultMap(entityMapper.getNamespace() + "." + Constants.BASE_RESULT_MAP));
						statementBuilder.resultMaps(resultMaps);
					}
					statementBuilder.keyColumn(entityMapper.getKeyColumn());
					statementBuilder.keyProperty(entityMapper.getKeyProperty());
					if (entityMapper.isUseGeneratedKeys()) {
						statementBuilder.keyGenerator(new Jdbc3KeyGenerator());
					}
					MappedStatement statement = statementBuilder.build();
					configuration.addMappedStatement(statement);
				}
			}
		}
	}

}
